package com.java.base.exercise.current.alarmsystem;

import java.util.Queue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

/**
 * @Author RenPu
 * @Date 2022/1/7 16:34
 * @Version 1.0
 * @Description:
 *
 *     Guarded Suspension模式的“等待-通知”机制是一种非常普遍的线程间协作的方式。
 *     我们在平时工作中经常看到有同学使用“轮询while(true)”的方式来等待某个状态，
 *     其实都可以用这个“等待-通知”机制来优化。
 *
 *
 * Notify()和notifyAll()这两者是有区别的，notify() 是会随机地通知等待队列中的任意一个线程，
 * 而 notifyAll() 会通知等待队列中的所有线程。
 *
 *
 * 觉得 notify() 会更好一些的同学可能认为即便通知所有线程，也只有一个线程能够进入临界区。但是实际上使用 notify() 也很有风险，
 * 因为随机通知等待的线程，可能会导致某些线程永远不会被通知到。
 *
 * 所以除非经过深思熟虑，否则尽量使用 notifyAll()。
 *
 *  自定义实现阻塞队列
 **/
public class GuardedQueue {

    private final Queue<Integer> sourceList;

    public GuardedQueue() {
        this.sourceList = new LinkedBlockingQueue<>();
    }

    public synchronized Integer get() {
        while (sourceList.isEmpty()) {
            try {
                wait();    // <--- 如果队列为null，等待
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return sourceList.peek();
    }

    public synchronized void put(Integer e) {
        sourceList.add(e);
        notifyAll();  //<--- 通知，继续执行    }
    }



    //测试
    public static void main(String[] args) {

        GuardedQueue guardedQueue = new GuardedQueue();
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        executorService.execute(() -> {
                    guardedQueue.get();
                }
        );
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        executorService.execute(() -> {
                    guardedQueue.put(20);
                }
        );
        executorService.shutdown();
        try {
            executorService.awaitTermination(30, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
